package com.weasel.weixin.commons.session.mgt;

import com.weasel.weixin.commons.exception.StringEmptyException;
import com.weasel.weixin.commons.exception.UnknowSessionException;
import com.weasel.weixin.commons.session.WeixinSession;
import com.weasel.weixin.commons.session.factory.SessionFactory;
import com.weasel.weixin.commons.session.factory.SimpleSessionFactory;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by Dylan on 2015/12/7.
 */
public abstract class AbstractWeixinSessionManager implements WeixinSessionManager {

    private final static Logger logger = LoggerFactory.getLogger(AbstractWeixinSessionManager.class);

    protected static final long MILLIS_PER_SECOND = 1000;   //1秒钟
    protected static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND;  //1分钟
    protected static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE;   //1小时

    public static final long DEFAULT_GLOBAL_SESSION_TIMEOUT = 30 * MILLIS_PER_MINUTE;

    protected long globalSessionTimeout = DEFAULT_GLOBAL_SESSION_TIMEOUT;

    protected SessionFactory sessionFactory;

    public AbstractWeixinSessionManager() {
        sessionFactory = new SimpleSessionFactory();
    }

    /**
     * @return
     */
    public long getGlobalSessionTimeout() {
        return globalSessionTimeout;
    }

    /**
     * @param globalSessionTimeout
     */
    public void setGlobalSessionTimeout(long globalSessionTimeout) {
        this.globalSessionTimeout = globalSessionTimeout;
    }

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    @Override
    public WeixinSession start(String sessionid) {

        if(logger.isDebugEnabled()){
            logger.debug("start session with id [{}]",sessionid);
        }
        return createSession(sessionid);
    }

    @Override
    public WeixinSession getSession(String sessionid) {
        return getSession(sessionid,false);
    }

    @Override
    public WeixinSession getSession(String sessionid, boolean create) {

        WeixinSession session = lookupSession(sessionid);
        if(null == session && create){
            session = createSession(sessionid);
        }
        return session;
    }

    protected WeixinSession createSession(String sessionid){
        WeixinSession session = sessionFactory.create(sessionid);
        session.setTimeout(getGlobalSessionTimeout());
        doCreateSession(session);
        return session;
    }

    protected void doCreateSession(WeixinSession session){
        //do nothing
    }

    private WeixinSession lookupSession(String sessionid){

        if(StringUtils.isEmpty(sessionid)){
            String msg = "sessionid can not be empty";
            throw new StringEmptyException(msg);
        }
        return doGetSession(sessionid);
    }

    private WeixinSession lookupRequiredSession(String sessionid){
        WeixinSession session = lookupSession(sessionid);

        if(null == session){
            String msg = "can not lookup session with id["+sessionid+"]";
            throw new UnknowSessionException(msg);
        }
        return session;
    }

    protected abstract WeixinSession doGetSession(String sessionid);

    @Override
    public void stop(String sessionid) {
        WeixinSession session = lookupRequiredSession(sessionid);

        if(logger.isDebugEnabled()){
            logger.debug("stop session with id [{}]",sessionid);
        }
        session.stop();
        onStop(session);
    }

    protected void onStop(WeixinSession session){
        try {
            onChange(session);
        }finally {
            afterStop(session);
        }
    }

    protected void afterStop(WeixinSession session){

    }

    /**
     * @param session
     */
    protected void onChange(WeixinSession session){
        //do noting
    };
}
